#include <string>
#include "ProSpace.h"
#include "Measurer.h"
//using namespace std;

ProSpace::ProSpace(string varname[], int varvalue[], float probability, int count){
	
	m_varname = new string[count+2]; // the last variable is tmp store for LIT
	m_varvalue = new int[count+2]; // the last variable is tmp store for LIT
	m_comparevalue = 0;
	for(int i=0; i< count;i++){
		m_varname[i] = varname[i].substr(0);
	}
	for(int i=0; i< count;i++){
		m_varvalue[i] = varvalue[i]; 
	}
	m_varname[count] = "TMP";
	m_varvalue[count] = 0;
	m_varname[count+1] = "TMP2";
	m_varvalue[count+1] = 0;
	m_probability = probability;
	m_count = count+2;
}
ProSpace::ProSpace(string varname, int varvalue, float probability, int count){
	m_varname = new string[1];
	m_varvalue = new int[1];
	m_varname[0] = varname;
	m_varvalue[0]=varvalue;
	m_probability = probability;
	m_count =count;
}
ProSpace::ProSpace(string varname){
	m_varname = new string[1];
	m_varvalue = new int[1];
	m_varname[0] = varname;
	m_varvalue[0]=0;
	m_probability = 0;
	m_count =1;
}


ProSpace ProSpace::getVarSpace(string varname){
	return ProSpace(varname,m_varvalue[getIndex(varname)],m_probability,1);
}

void ProSpace::setValue(string varname, int value){

	m_varvalue[getIndex(varname)] = value;
}
// the getIndex(varname)+2 only work for 2 variables
void ProSpace::updateByTmp(string varname){
	//setValue(varname, m_varvalue[getIndex(varname)+2]);
	
	setValue(varname,m_varvalue[2]);
	clearBuffer(m_varname[getIndex(varname)+2]);
	clearBuffer(m_varname[m_count-2]);
}
void ProSpace::updateByTmp(string from, string to){
	int intFrom = m_varvalue[getIndex(from)];
	setValue(to, intFrom);
	//clearBuffer(m_varname[getIndex(varname)+2]);
}


void ProSpace::clearBuffer(string varname){
	setValue(varname,0);	
}



int ProSpace::getIndex(string varname){
	for(int i=0; i<m_count;i++){
		if(!(m_varname[i].compare(varname))){
			return i;			
		}
	}
	return -1;
}
void ProSpace::output(int index) const{
	//	printf("(%d)%d, w.p.,%f\n" ,m_varvalue[m_count-1],m_varvalue[index],m_probability);
}

void ProSpace::updateTmpValue(string varname, int op){
//	int value = m_varvalue[m_count-1];
	int dividor;
	switch(op){
	case ADD:
			m_varvalue[m_count-2]  =  m_varvalue[m_count-2] + m_varvalue[getIndex(varname)];		
			break;
	case SUB:
			m_varvalue[m_count-2]  =  m_varvalue[m_count-2] - m_varvalue[getIndex(varname)];		
			break;
	case MUL:
			m_varvalue[m_count-2]  =  m_varvalue[m_count-2] * m_varvalue[getIndex(varname)];		
			break;
	case DIVI:
			 dividor =m_varvalue[getIndex(varname)];
			if(dividor!=0){
				m_varvalue[m_count-2]  =  m_varvalue[m_count-2] / m_varvalue[getIndex(varname)];		

			}
			else{
				printf("Division by zero");
				exit(0);
			}
			break;
	
	case LTR:
		if(getValue(getIndex(varname))<m_varvalue[m_count-2] ){
			Measurer::addLeftChildNode(this);
			Measurer::addRightChildNode(0);
		}
		else{
			Measurer::addLeftChildNode(0);
			Measurer::addRightChildNode(this);
		}
		break;
	case GTR:
		if(getValue(getIndex(varname))>m_varvalue[m_count-2] ){
			Measurer::addLeftChildNode(this);
			Measurer::addRightChildNode(0);
		}
		else{
			Measurer::addLeftChildNode(0);
			Measurer::addRightChildNode(this);
		}
		break;
	default:	
		//	m_varvalue[m_count-1]  = 	 m_varvalue[m_count-2];			
		//m_varvalue[m_count-2] = m_varvalue[getIndex(varname)];
		
			m_varvalue[m_count-2] = m_varvalue[getIndex(varname)];
		
		break;
	}
	
}

void ProSpace::updateTmpValue(int v2, int op){
	int value = (m_varvalue[m_count-1]);
	
	
	switch(op){
	case ADD:
		m_varvalue[m_count-2]  =  (m_varvalue[m_count-2] +v2);
		
		break;
	case SUB:
		m_varvalue[m_count-2]  =  (m_varvalue[m_count-2] -v2);
		break;
	case MUL:
		m_varvalue[m_count-2]  =  (m_varvalue[m_count-2] *v2);
		break;
	case DIVI:
		if(v2!=0)
			m_varvalue[m_count-2]  =  (m_varvalue[m_count-2] /v2);
		else{
			printf("Division by zero");
			exit(0);
		}
		break;
	//case STO:
		//m_varvalue[m_count-2] += v2;
	//	break;
	case LIT:
		m_varvalue[m_count-1] =v2;
		break;
	case LTR:
		printf("%d<%d\n",m_varvalue[m_count-2],v2);
		if(m_varvalue[m_count-2]<v2){
			Measurer::addLeftChildNode(this);
			Measurer::addRightChildNode(0);
		}
		else{
			Measurer::addLeftChildNode(0);
			Measurer::addRightChildNode(this);
		}
		
		break;
	case GTR:
		printf("%d<%d\n",m_varvalue[m_count-2],v2);
		if(m_varvalue[m_count-2]>v2){
			Measurer::addLeftChildNode(this);
			Measurer::addRightChildNode(0);
		}
		else{
			Measurer::addLeftChildNode(0);
			Measurer::addRightChildNode(this);
		}
		
		break;
	default:
		m_varvalue[m_count-2]= v2;	
		break;
	}

	
}

const int ProSpace::getValue(int index) const{
		return m_varvalue[index];
		
	}
void ProSpace::setProbability(float pro){	
	m_probability = pro;
}
ProSpace ProSpace::operator+(const ProSpace& rhs){
	string varname[2];
	int varvalue[2];
	float p = 0.0;
	varname[0] = this->m_varname[0];
	varname[1] = rhs.m_varname[0];
	varname[1] +="'";
	varvalue[0] = this->m_varvalue[0];
	varvalue[1] = rhs.m_varvalue[0];
	p = this->m_probability * rhs.m_probability;
	//ProSpace lhs(varname,varvalue,p,2);
	
	/*lhs.m_varname[1] = rhs.m_varname[0] +"'";
	lhs.m_varvalue[1] = rhs.m_varvalue[0];
	lhs.m_probability *=rhs.m_probability;
	lhs.m_count = 2;*/

	//ProSpace* space = new ProSpace(varname, varvalue, sp.m_probability*sp2.m_probability,2);
	return ProSpace (varname,varvalue,p,2);
}
ProSpace& ProSpace::operator=(const ProSpace& rhs){
	m_varname = new string[1];
	m_varvalue = new int[1];
	
	m_varname[0] = rhs.m_varname[0];
	
	
	m_varvalue[0] = rhs.m_varvalue[0];
	
	m_probability = rhs.m_probability;
	m_count = rhs.m_count;
	//return ProSpace (varname,varvalue,p,2);
	return *this;
}

ostream& operator<<(ostream& out, const ProSpace& space){
	//printf("(%d)%d, w.p.,%f\n" ,m_varvalue[m_count-1],m_varvalue[index],m_probability);
	/*for(int i=0; i< space.m_count;i++){
		cout << space.m_varname[i] <<",";
	}
	cout << "probability" << endl;*/
	
	for(int i=0; i< space.m_count;i++){
		out <<space.m_varvalue[i] <<",";
	}
	out << "w.p." << space.m_probability << endl;
	return out;
}

ProSpace::ProSpace(){
	m_varname = 0;
	m_varvalue = 0;
	m_probability=0.0;
	m_count = 0;
}
ProSpace::~ProSpace(){
	
	delete[] m_varname;
	delete[] m_varvalue;
	
	m_varname = 0;
	m_varvalue = 0;

}
ProSpace::ProSpace(const ProSpace&ps){
	
	m_varname = new string[ps.m_count+2]; // the last variable is tmp store for LIT
	m_varvalue = new int[ps.m_count+2]; // the last variable is tmp store for LIT
	m_count = ps.m_count;
	for(int i=0; i< ps.m_count;i++){
		m_varname[i] = ps.m_varname[i].substr(0);
	}
	for(int i=0; i< ps.m_count;i++){
		m_varvalue[i] = ps.m_varvalue[i];
	}
	/*m_varname[count] = "TMP";
	m_varvalue[count] = 0;
	m_varname[count+1] = "TMP2";
	m_varvalue[count+1] = 0;*/
	m_probability = ps.m_probability;
	//m_count = count+2;

}
void ProSpace::updateCmpValue(int value){
	m_comparevalue = value;
}